// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: GPL-3.0-only

package service_cmd

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"

	"gitcode.com/openseaotter/so_proto_gen_go.git/admin_api"
	"gitcode.com/openseaotter/so_proto_gen_go.git/auth_secret_api"
	"gitcode.com/openseaotter/so_proto_gen_go.git/config_api"
	"gitcode.com/openseaotter/so_proto_gen_go.git/image_api"
	"gitcode.com/openseaotter/so_proto_gen_go.git/image_group_api"
	"gitcode.com/openseaotter/so_proto_gen_go.git/member_api"
	"gitcode.com/openseaotter/so_proto_gen_go.git/watch_api"
	"gitcode.com/openseaotter/so_server/api_impl/admin_api_impl"
	"gitcode.com/openseaotter/so_server/api_impl/auth_secret_api_impl"
	"gitcode.com/openseaotter/so_server/api_impl/config_api_impl"
	"gitcode.com/openseaotter/so_server/api_impl/image_api_impl"
	"gitcode.com/openseaotter/so_server/api_impl/image_group_api_impl"
	"gitcode.com/openseaotter/so_server/api_impl/member_api_impl"
	"gitcode.com/openseaotter/so_server/api_impl/watch_agent_api_impl"
	"gitcode.com/openseaotter/so_server/api_impl/watch_api_impl"
	"gitcode.com/openseaotter/so_server/config"
	"gitcode.com/openseaotter/so_server/service_impl"
	"gitcode.com/openseaotter/so_server/storage"
	"gitcode.com/openseaotter/so_server/utils"
	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
	"github.com/spf13/cobra"
	"google.golang.org/grpc"
)

var runCmd = &cobra.Command{
	Use:  "run",
	RunE: doRunService,
}

func doRunService(cmd *cobra.Command, args []string) error {
	cfg, err := config.ReadServerConfigFromCache()
	if err != nil {
		return err
	}

	err = processPidFile()
	if err != nil {
		return err
	}

	defer os.Remove(utils.PID_FILE_PATH)

	err = storage.InitBadgerDb()
	if err != nil {
		return err
	}
	storage.InitLocalStore()
	storage.InitUploadStore()
	storage.InitChangeNoticeDao()

	exitChan := make(chan error, 10)

	go service_impl.Run(cfg.HttpPort, exitChan)
	if cfg.HttpTlsPort > 0 && cfg.TlsCertFile != "" && cfg.TlsKeyFile != "" {
		go service_impl.RunTls(cfg.HttpTlsPort, cfg.TlsCertFile, cfg.TlsKeyFile, exitChan)
	}

	go runApiServ(cfg.ServicePort, exitChan)

	go func() {
		sigChan := make(chan os.Signal, 1)
		signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)
		for {
			sig := <-sigChan
			if sig == syscall.SIGHUP {
				config.MarkServerConfigChange()
			} else {
				exitChan <- errors.New("catch signal")
			}
		}
	}()

	for {
		err = <-exitChan
		if err != nil {
			return err
		}
	}
}

func processPidFile() error {
	oldPid, err := utils.LoadPid()
	if err == nil { //可能存在老进程
		p, _ := os.FindProcess(oldPid) //在linux上总是成功返回
		err = p.Signal(syscall.Signal(0))
		if err == nil { //存在老进程
			return fmt.Errorf("allread running")
		}
		os.Remove(utils.PID_FILE_PATH)
	}
	return utils.StorePid()
}

func runApiServ(port uint16, exitChan chan<- error) {
	optionList := []grpc.ServerOption{
		grpc.StreamInterceptor(
			grpc_middleware.ChainStreamServer(
				grpc_recovery.StreamServerInterceptor(),
			)),
		grpc.UnaryInterceptor(
			grpc_middleware.ChainUnaryServer(
				grpc_recovery.UnaryServerInterceptor(),
			)),
		grpc.InitialConnWindowSize(1 << 30),
		grpc.InitialWindowSize(1 << 30),
	}
	grpcServer := grpc.NewServer(optionList...)

	auth_secret_api.RegisterAuthSecretApiServer(grpcServer, &auth_secret_api_impl.AuthSecretApiImpl{})
	image_group_api.RegisterImageGroupApiServer(grpcServer, &image_group_api_impl.ImageGroupApiImpl{})
	image_api.RegisterImageApiServer(grpcServer, &image_api_impl.ImageApiImpl{})
	member_api.RegisterMemberApiServer(grpcServer, &member_api_impl.MemberApiImpl{})
	config_api.RegisterConfigApiServer(grpcServer, &config_api_impl.ConfigApiImpl{})
	admin_api.RegisterAdminApiServer(grpcServer, &admin_api_impl.AdminApiImpl{})
	watch_api.RegisterWatchApiServer(grpcServer, &watch_api_impl.WatchApiImpl{})
	watch_api.RegisterWatchAgentApiServer(grpcServer, &watch_agent_api_impl.WatchAgentApiImpl{})

	addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("0.0.0.0:%d", port))
	if err != nil {
		exitChan <- err
		return
	}
	li, err := net.ListenTCP("tcp4", addr)
	if err != nil {
		exitChan <- err
		return
	}
	fmt.Println("service start......")
	err = grpcServer.Serve(li)
	if err != nil {
		exitChan <- err
		return
	}
}
